
#include <BReadWrite>
#include <BScene>

#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BGroupBox>
#include <BFileDialog>
#include <BImage>
#include <BListItem>
#include <BGridLayout>

#include "ModifyDialog.h"

ModifyDialog::ModifyDialog(BWidget* parent) : BDialog(parent)
{
	BGroupBox* objectsGroupBox = new BGroupBox("Objects");
	{
		_selectedObjectsRadioBox = new BRadioBox("Selected Objects");
		_allObjectsRadioBox = new BRadioBox("All Objects");

		_objectsGroup = new BButtonGroup();
		_objectsGroup->addButton(_selectedObjectsRadioBox);
		_objectsGroup->addButton(_allObjectsRadioBox);

		BVBoxLayout* vlayout = new BVBoxLayout(objectsGroupBox);
		vlayout->addWidget(_selectedObjectsRadioBox);
		vlayout->addWidget(_allObjectsRadioBox);
		vlayout->addSpring();
	}

	BGroupBox* operateGroupBox = new BGroupBox("Operation");
	{
		_swapYZButton = new BButton("SwapYZ");

		BHBoxLayout* scaleLayout = new BHBoxLayout();
		{
			BLabel* ratioLabel = new BLabel("ratio");
			_scaleRatioSpinBox = new BDoubleSpinBox();
			_scaleButton = new BButton("scale");

			scaleLayout->addWidget(ratioLabel);
			scaleLayout->addWidget(_scaleRatioSpinBox, 10);
			scaleLayout->addWidget(_scaleButton, 0);
		}
		BVBoxLayout* vlayout = new BVBoxLayout(operateGroupBox);
		vlayout->addWidget(_swapYZButton);
		vlayout->addLayout(scaleLayout);
	}

	BVBoxLayout* centerLayout = new BVBoxLayout(this);
	centerLayout->addWidget(objectsGroupBox, 0);
	centerLayout->addWidget(operateGroupBox, 0);
	centerLayout->addSpring();
	centerLayout->setSpacing(3);

	connect(_objectsGroup, Signal_Checked, &ModifyDialog::slotObjectsGroupChecked);
	connect(_swapYZButton, Signal_Clicked, &ModifyDialog::slotSwapYZClicked);
	connect(_scaleRatioSpinBox, Signal_ValueEdited, &ModifyDialog::slotScaleRatioEdited);
	connect(_scaleButton, Signal_Clicked, &ModifyDialog::slotScaleButtonClicked);
}
ModifyDialog::~ModifyDialog()
{

}

void ModifyDialog::setSceneTree(BTreeWidget* sceneTree)
{
	_sceneTree = sceneTree;
	_scaleRatioSpinBox->setValue(1.0);
	_scaleButton->setEnabled(false);
	_swapYZButton->setEnabled(true);
}
BTreeWidget* ModifyDialog::sceneTree() const
{
	return _sceneTree;
}

void ModifyDialog::swapGroupYZ(BGroup* group)
{
	for (int i = 0; i < group->shapeCount(); i++)
	{
		swapShapeYZ(group->shape(i));
	}
	for (int i = 0; i < group->nodeCount(); i++)
	{
		swapNodeYZ(group->node(i));
	}
	for (int i = 0; i < group->childCount(); i++)
	{
		swapGroupYZ(group->child(i));
	}
}
void ModifyDialog::swapNodeYZ(BNode* node)
{
	for (int i = 0; i < node->shapeCount(); i++)
	{
		swapShapeYZ(node->shape(i));
	}
}
void ModifyDialog::swapShapeYZ(BShape* shape)
{
	if (BGeometry* geometry = dynamic_cast<BGeometry*>(shape))
		swapGeometryYZ(geometry);
	else if (BMesh* mesh = dynamic_cast<BMesh*>(shape))
		swapMeshYZ(mesh);
}
void ModifyDialog::swapMeshYZ(BMesh* mesh)
{
	BVectorArray* vertices = mesh->vertices();
	BVectorArray* normals = mesh->normals();
	for (int i = 0; i < vertices->size(); i++)
	{
		BVector& v = vertices->at(i);
		bSwap(v.y(), v.z());
		BVector& n = normals->at(i);
		bSwap(n.y(), n.z());
	}
	mesh->setVertices(vertices);

	if (BFaceArray* faces = mesh->faces())
	{
		int size = faces->size();
		for (int i = 0; i < size; i++)
		{
			BFace& face = (*faces)[i];
			bSwap(face.b(), face.c());
		}
	}
	else
	{
		int size = vertices->size();
		for (int i = 0; i < size; i += 3)
		{
			BVector& vb = (*vertices)[i + 1];
			BVector& vc = (*vertices)[i + 2];
			bSwap(vb, vc);
		}
	}

	return;
}
void ModifyDialog::swapGeometryYZ(BGeometry* geometry)
{
	BVectorArray* vertices = geometry->vertices();
	BVectorArray* normals = geometry->normals();
	for (int i = 0; i < vertices->size(); i++)
	{
		BVector& v = vertices->at(i);
		bSwap(v.y(), v.z());
		BVector& n = normals->at(i);
		bSwap(n.y(), n.z());
	}
	geometry->setVertices(vertices);

	for (int i = 0; i < geometry->elementCount(); i++)
	{
		BElement* element = geometry->element(i);
		int first = element->first();
		int count = element->count();
		if (BIntArray* indices = element->indices())
		{
			if (element->primitive() == Primitive_Triangles)
			{
				for (int i = 0; i < count; i += 3)
				{
					int& ia = (*indices)[first + i];
					int& ib = (*indices)[first + i + 1];
					bSwap(ia, ib);
				}
			}
			if (element->primitive() == Primitive_Quads)
			{
				for (int i = 0; i < count; i += 4)
				{
					int& ib = (*indices)[first + i + 1];
					int& id = (*indices)[first + i + 3];
					bSwap(ib, id);
				}
			}
		}
		if (BPieceArray* pieces = element->pieces())
		{
			if (element->primitive() == Primitive_Triangles)
			{
				for (int i = 0; i < pieces->size(); i += 3)
				{
					BPiece& pa = (*pieces)[i];
					BPiece& pb = (*pieces)[i + 1];
					bSwap(pa, pb);
				}
			}
			if (element->primitive() == Primitive_Quads)
			{
				for (int i = 0; i < pieces->size(); i += 4)
				{
					BPiece& pb = (*pieces)[first + i + 1];
					BPiece& pd = (*pieces)[first + i + 3];
					bSwap(pb, pd);
				}
			}
		}
	}
	return;
}

void ModifyDialog::scaleShape(BShape* shape)
{
	float ratio = (float)_scaleRatioSpinBox->value();
	if (BGeometry* geometry = dynamic_cast<BGeometry*>(shape))
	{
		BVectorArray* vertices = geometry->vertices();
		for (int i = 0; i < vertices->size(); i++)
		{
			BVector& v = vertices->at(i);
			v *= ratio;
		}
		geometry->setVertices(vertices);
		return;
	}
	if (BMesh* mesh = dynamic_cast<BMesh*>(shape))
	{
		BVectorArray* vertices = mesh->vertices();
		for (int i = 0; i < vertices->size(); i++)
		{
			BVector& v = vertices->at(i);
			v *= ratio;
		}
		mesh->setVertices(vertices);
		return;
	}
}

void ModifyDialog::slotObjectsGroupChecked()
{

}
void ModifyDialog::slotScaleRatioEdited()
{
	float ratio = (float)_scaleRatioSpinBox->value();
	_scaleButton->setEnabled(bNonZero(ratio - 1.0f));
}
void ModifyDialog::slotScaleButtonClicked()
{
	if (_selectedObjectsRadioBox->checked())
	{
		for (int i = 0; i < _sceneTree->selectedItemCount(); i++)
		{
			BTreeItem* item = _sceneTree->selectedItem(i);
			if (BShape* shape = item->asset())
			{
				scaleShape(shape);
			}
			if (BNode* node = item->asset())
			{
				for (int si = 0; si < node->shapeCount(); si++)
				{
					BShape* shape = node->shape(si);
					scaleShape(shape);
				}
			}
		}
	}
	else
	{
		BScene* scene = _sceneTree->asset();
		for (int i = 0; i < scene->shapeCount(); i++)
		{
			BShape* shape = scene->shape(i);
			scaleShape(shape);
		}
		for (int i = 0; i < scene->nodeCount(); i++)
		{
			BNode* node = scene->node(i);
			for (int si = 0; si < node->shapeCount(); si++)
			{
				BShape* shape = node->shape(si);
				scaleShape(shape);
			}
		}
	}
	_scaleRatioSpinBox->setValue(1);
}
void ModifyDialog::slotSwapYZClicked()
{
	if (_selectedObjectsRadioBox->checked())
	{
		for (int i = 0; i < _sceneTree->selectedItemCount(); i++)
		{
			BTreeItem* item = _sceneTree->selectedItem(i);
			BObject* object = item->asset();
			if (BShape* shape = dynamic_cast<BShape*>(object))
			{
				swapShapeYZ(shape);
			}
			if (BNode* node = dynamic_cast<BNode*>(object))
			{
				swapNodeYZ(node);
			}
			if (BGroup* group = dynamic_cast<BGroup*>(object))
			{
				swapGroupYZ(group);
			}
		}
	}
	else
	{
		BScene* scene = _sceneTree->asset();
		for (int i = 0; i < scene->shapeCount(); i++)
		{
			swapShapeYZ(scene->shape(i));
		}
		for (int i = 0; i < scene->nodeCount(); i++)
		{
			swapNodeYZ(scene->node(i));
		}
		for (int i = 0; i < scene->groupCount(); i++)
		{
			swapGroupYZ(scene->group(i));
		}
	}
}

void ModifyDialog::showEvent(const BEvent& event)
{
	BDialog::showEvent(event);
	if (_objectsGroup->checkedButton() == 0)
	{
		if (_sceneTree->selectedItemCount() == 0)
			_allObjectsRadioBox->setChecked(true);
		else
			_selectedObjectsRadioBox->setChecked(true);
	}
}

void ModifyDialog::paintEvent(const BEvent& event)
{
	BDialog::paintEvent(event);
}
